package wuziqi;

import java.util.*;

// 通用专业AI - 适用于不同胜利条件的棋盘游戏
class UniversalProfessionalAI implements AI {
    private Random random = new Random();
    
    @Override
    public int[] makeMove(GameState state, GameConfig config) {
        char[][] board = state.getBoard();
        char aiPlayer = state.getCurrentPlayer();
        char humanPlayer = (aiPlayer == config.getPlayer1Symbol()) ? 
                          config.getPlayer2Symbol() : config.getPlayer1Symbol();
        int winCount = config.getWinCount();
        
        // 根据胜利条件调整策略
        if (winCount <= 3) {
            return makeMoveForShortWin(board, aiPlayer, humanPlayer, config);
        } else if (winCount >= 6) {
            return makeMoveForLongWin(board, aiPlayer, humanPlayer, config);
        } else {
            return makeMoveForMediumWin(board, aiPlayer, humanPlayer, config);
        }
    }
    
    // 短连线游戏策略（如井字棋）
    private int[] makeMoveForShortWin(char[][] board, char aiPlayer, char humanPlayer, GameConfig config) {
        int winCount = config.getWinCount();
        
        // 1. 立即获胜
        int[] winMove = findImmediateWin(board, aiPlayer, winCount, config);
        if (winMove != null) return winMove;
        
        // 2. 阻止对手获胜
        int[] blockMove = findImmediateWin(board, humanPlayer, winCount, config);
        if (blockMove != null) return blockMove;
        
        // 3. 创建双重威胁
        int[] forkMove = findForkMove(board, aiPlayer, humanPlayer, winCount, config);
        if (forkMove != null) return forkMove;
        
        // 4. 阻止对手的双重威胁
        int[] blockFork = findForkMove(board, humanPlayer, aiPlayer, winCount, config);
        if (blockFork != null) return blockFork;
        
        // 5. 基于评分选择
        return findBestScoredMove(board, aiPlayer, humanPlayer, config);
    }
    
    // 中等连线游戏策略（如五子棋）
    private int[] makeMoveForMediumWin(char[][] board, char aiPlayer, char humanPlayer, GameConfig config) {
        int winCount = config.getWinCount();
        
        // 1. 立即获胜
        int[] winMove = findImmediateWin(board, aiPlayer, winCount, config);
        if (winMove != null) return winMove;
        
        // 2. 阻止对手立即获胜
        int[] blockWin = findImmediateWin(board, humanPlayer, winCount, config);
        if (blockWin != null) return blockWin;
        
        // 3. 检查高级威胁
        int[] advancedThreat = findAdvancedThreat(board, humanPlayer, aiPlayer, winCount, config);
        if (advancedThreat != null) return advancedThreat;
        
        // 4. 创建进攻机会
        int[] offensiveMove = createOffensiveOpportunity(board, aiPlayer, humanPlayer, winCount, config);
        if (offensiveMove != null) return offensiveMove;
        
        // 5. 基于评分选择
        return findBestScoredMove(board, aiPlayer, humanPlayer, config);
    }
    
    // 长连线游戏策略（如六子棋）
    private int[] makeMoveForLongWin(char[][] board, char aiPlayer, char humanPlayer, GameConfig config) {
        int winCount = config.getWinCount();
        
        // 长连线游戏更注重位置控制和长期规划
        return findStrategicMove(board, aiPlayer, humanPlayer, winCount, config);
    }
    
    // 查找立即获胜的机会
    private int[] findImmediateWin(char[][] board, char player, int winCount, GameConfig config) {
        List<int[]> emptyPositions = getStrategicEmptyPositions(board, config);
        
        for (int[] pos : emptyPositions) {
            board[pos[0]][pos[1]] = player;
            if (checkWinAtPosition(board, pos[0], pos[1], winCount)) {
                board[pos[0]][pos[1]] = config.getEmptySymbol();
                return pos;
            }
            board[pos[0]][pos[1]] = config.getEmptySymbol();
        }
        return null;
    }
    
    // 查找分叉移动（创造多个威胁）
    private int[] findForkMove(char[][] board, char player, char opponent, int winCount, GameConfig config) {
        List<int[]> emptyPositions = getStrategicEmptyPositions(board, config);
        Map<int[], Integer> forkScores = new HashMap<>();
        
        for (int[] pos : emptyPositions) {
            board[pos[0]][pos[1]] = player;
            int threatCount = countImmediateThreats(board, pos[0], pos[1], player, winCount, config);
            board[pos[0]][pos[1]] = config.getEmptySymbol();
            
            if (threatCount >= 2) {
                forkScores.put(pos, threatCount);
            }
        }
        
        if (!forkScores.isEmpty()) {
            return Collections.max(forkScores.entrySet(), Map.Entry.comparingByValue()).getKey();
        }
        return null;
    }
    
    // 查找高级威胁（活三、冲四等）
    private int[] findAdvancedThreat(char[][] board, char opponent, char aiPlayer, int winCount, GameConfig config) {
        List<int[]> emptyPositions = getStrategicEmptyPositions(board, config);
        Map<int[], Integer> threatLevels = new HashMap<>();
        
        for (int[] pos : emptyPositions) {
            // 检查对手在这个位置的威胁等级
            board[pos[0]][pos[1]] = opponent;
            int threatLevel = evaluateThreatLevel(board, pos[0], pos[1], opponent, winCount, config);
            board[pos[0]][pos[1]] = config.getEmptySymbol();
            
            if (threatLevel > 0) {
                threatLevels.put(pos, threatLevel);
            }
        }
        
        if (!threatLevels.isEmpty()) {
            return Collections.max(threatLevels.entrySet(), Map.Entry.comparingByValue()).getKey();
        }
        return null;
    }
    
    // 创建进攻机会
    private int[] createOffensiveOpportunity(char[][] board, char aiPlayer, char opponent, int winCount, GameConfig config) {
        List<int[]> emptyPositions = getStrategicEmptyPositions(board, config);
        Map<int[], Integer> opportunityScores = new HashMap<>();
        
        for (int[] pos : emptyPositions) {
            board[pos[0]][pos[1]] = aiPlayer;
            int opportunityScore = evaluateOpportunity(board, pos[0], pos[1], aiPlayer, winCount, config);
            board[pos[0]][pos[1]] = config.getEmptySymbol();
            
            if (opportunityScore > 0) {
                opportunityScores.put(pos, opportunityScore);
            }
        }
        
        if (!opportunityScores.isEmpty()) {
            return Collections.max(opportunityScores.entrySet(), Map.Entry.comparingByValue()).getKey();
        }
        return null;
    }
    
    // 查找战略性移动（适用于长连线游戏）
    private int[] findStrategicMove(char[][] board, char aiPlayer, char opponent, int winCount, GameConfig config) {
        List<int[]> emptyPositions = getStrategicEmptyPositions(board, config);
        Map<int[], Integer> strategicScores = new HashMap<>();
        
        for (int[] pos : emptyPositions) {
            int score = evaluateStrategicPosition(board, pos[0], pos[1], aiPlayer, opponent, winCount, config);
            strategicScores.put(pos, score);
        }
        
        return Collections.max(strategicScores.entrySet(), Map.Entry.comparingByValue()).getKey();
    }
    
    // 基于评分选择最佳位置（通用方法）
    private int[] findBestScoredMove(char[][] board, char aiPlayer, char opponent, GameConfig config) {
        List<int[]> emptyPositions = getStrategicEmptyPositions(board, config);
        Map<int[], Integer> moveScores = new HashMap<>();
        
        for (int[] pos : emptyPositions) {
            int score = evaluateUniversalScore(board, pos[0], pos[1], aiPlayer, opponent, config);
            moveScores.put(pos, score);
        }
        
        return Collections.max(moveScores.entrySet(), Map.Entry.comparingByValue()).getKey();
    }
    
    // 通用位置评分
    private int evaluateUniversalScore(char[][] board, int row, int col, char player, char opponent, GameConfig config) {
        int score = 0;
        int winCount = config.getWinCount();
        
        // 基础位置价值
        score += getAdaptivePositionValue(row, col, config.getBoardSize(), winCount);
        
        // 进攻潜力
        board[row][col] = player;
        score += evaluateUniversalOffense(board, row, col, player, winCount, config);
        
        // 防守必要性
        board[row][col] = opponent;
        score += evaluateUniversalDefense(board, row, col, opponent, winCount, config) * 1.5;
        board[row][col] = config.getEmptySymbol();
        
        // 灵活性（空位周围的开放度）
        score += evaluateFlexibility(board, row, col, config);
        
        return score;
    }
    
    // 自适应位置价值
    private int getAdaptivePositionValue(int row, int col, int boardSize, int winCount) {
        int center = boardSize / 2;
        int distanceFromCenter = Math.abs(row - center) + Math.abs(col - center);
        
        // 根据胜利条件调整中心价值
        double centerWeight;
        if (winCount <= 3) {
            centerWeight = 1.5; // 短连线游戏中心更重要
        } else if (winCount >= 6) {
            centerWeight = 0.8; // 长连线游戏中心价值相对降低
        } else {
            centerWeight = 1.0; // 中等连线游戏
        }
        
        return (int)((boardSize - distanceFromCenter) * 3 * centerWeight);
    }
    
    // 通用进攻评估
    private int evaluateUniversalOffense(char[][] board, int row, int col, char player, int winCount, GameConfig config) {
        int offenseScore = 0;
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};
        
        for (int[] dir : directions) {
            PatternInfo pattern = analyzePattern(board, row, col, dir[0], dir[1], player, winCount, config);
            offenseScore += pattern.getOffenseScore();
        }
        
        return offenseScore;
    }
    
    // 通用防守评估
    private int evaluateUniversalDefense(char[][] board, int row, int col, char opponent, int winCount, GameConfig config) {
        int defenseScore = 0;
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};
        
        for (int[] dir : directions) {
            PatternInfo pattern = analyzePattern(board, row, col, dir[0], dir[1], opponent, winCount, config);
            defenseScore += pattern.getDefenseScore();
        }
        
        return defenseScore;
    }
    
    // 分析模式信息
    private PatternInfo analyzePattern(char[][] board, int row, int col, int rowDir, int colDir, 
                                     char player, int winCount, GameConfig config) {
        int consecutive = 1; // 当前位置
        int openEnds = 0;
        char empty = config.getEmptySymbol();
        
        // 正向分析
        int r = row + rowDir;
        int c = col + colDir;
        boolean forwardBlocked = false;
        int forwardSteps = 0;
        
        while (!forwardBlocked && forwardSteps < winCount - 1 && 
               r >= 0 && r < board.length && c >= 0 && c < board[0].length) {
            if (board[r][c] == player) {
                consecutive++;
            } else if (board[r][c] == empty) {
                openEnds++;
                forwardBlocked = true;
            } else {
                forwardBlocked = true; // 被阻挡
            }
            r += rowDir;
            c += colDir;
            forwardSteps++;
        }
        
        // 如果正向没有被阻挡且没有遇到空位，检查是否还有空位
        if (!forwardBlocked && r >= 0 && r < board.length && c >= 0 && c < board[0].length && 
            board[r][c] == empty) {
            openEnds++;
        }
        
        // 反向分析
        r = row - rowDir;
        c = col - colDir;
        boolean backwardBlocked = false;
        int backwardSteps = 0;
        
        while (!backwardBlocked && backwardSteps < winCount - 1 && 
               r >= 0 && r < board.length && c >= 0 && c < board[0].length) {
            if (board[r][c] == player) {
                consecutive++;
            } else if (board[r][c] == empty) {
                openEnds++;
                backwardBlocked = true;
            } else {
                backwardBlocked = true; // 被阻挡
            }
            r -= rowDir;
            c -= colDir;
            backwardSteps++;
        }
        
        // 如果反向没有被阻挡且没有遇到空位，检查是否还有空位
        if (!backwardBlocked && r >= 0 && r < board.length && c >= 0 && c < board[0].length && 
            board[r][c] == empty) {
            openEnds++;
        }
        
        return new PatternInfo(consecutive, openEnds, winCount);
    }
    
    // 评估机会分数
    private int evaluateOpportunity(char[][] board, int row, int col, char player, int winCount, GameConfig config) {
        int opportunity = 0;
        
        // 检查是否能创建多个威胁
        int threatCount = countImmediateThreats(board, row, col, player, winCount, config);
        opportunity += threatCount * 30;
        
        // 检查是否能控制关键区域
        opportunity += evaluateControl(board, row, col, player, config);
        
        return opportunity;
    }
    
    // 评估战略性位置
    private int evaluateStrategicPosition(char[][] board, int row, int col, char player, char opponent, int winCount, GameConfig config) {
        int strategicValue = 0;
        
        // 长期规划价值
        strategicValue += evaluateLongTermPotential(board, row, col, player, winCount, config);
        
        // 阻碍对手发展
        strategicValue += evaluateObstruction(board, row, col, opponent, winCount, config);
        
        // 位置灵活性
        strategicValue += evaluateFlexibility(board, row, col, config);
        
        return strategicValue;
    }
    
    // 评估灵活性
    private int evaluateFlexibility(char[][] board, int row, int col, GameConfig config) {
        int flexibility = 0;
        char empty = config.getEmptySymbol();
        
        // 检查周围空位数量
        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                if (i == 0 && j == 0) continue;
                int r = row + i;
                int c = col + j;
                if (r >= 0 && r < board.length && c >= 0 && c < board[0].length && 
                    board[r][c] == empty) {
                    flexibility += 5;
                }
            }
        }
        
        return flexibility;
    }
    
    // 计算立即威胁数量
    private int countImmediateThreats(char[][] board, int row, int col, char player, int winCount, GameConfig config) {
        int threatCount = 0;
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};
        
        for (int[] dir : directions) {
            PatternInfo pattern = analyzePattern(board, row, col, dir[0], dir[1], player, winCount, config);
            
            // 根据胜利条件调整威胁判断
            if (pattern.consecutive >= winCount - 1 && pattern.openEnds >= 1) {
                threatCount++; // 差一步获胜
            } else if (pattern.consecutive >= winCount - 2 && pattern.openEnds >= 2) {
                threatCount++; // 双重威胁
            }
        }
        
        return threatCount;
    }
    
    // 评估威胁等级
    private int evaluateThreatLevel(char[][] board, int row, int col, char player, int winCount, GameConfig config) {
        int threatLevel = 0;
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};
        
        for (int[] dir : directions) {
            PatternInfo pattern = analyzePattern(board, row, col, dir[0], dir[1], player, winCount, config);
            
            // 根据胜利条件调整威胁等级
            if (pattern.consecutive >= winCount) {
                threatLevel += 1000; // 立即获胜
            } else if (pattern.consecutive == winCount - 1 && pattern.openEnds >= 1) {
                threatLevel += 500; // 活四或类似
            } else if (pattern.consecutive == winCount - 2 && pattern.openEnds >= 2) {
                threatLevel += 200; // 活三或类似
            } else if (pattern.consecutive == winCount - 2 && pattern.openEnds >= 1) {
                threatLevel += 100; // 冲三或类似
            } else if (pattern.consecutive >= 2) {
                threatLevel += pattern.consecutive * 10 + pattern.openEnds * 5;
            }
        }
        
        return threatLevel;
    }
    
    // 评估位置控制力
    private int evaluateControl(char[][] board, int row, int col, char player, GameConfig config) {
        int control = 0;
        int size = config.getBoardSize();
        char empty = config.getEmptySymbol();
        
        // 检查在多个方向的影响力
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}, {0,-1}, {-1,0}, {-1,-1}, {-1,1}};
        
        for (int[] dir : directions) {
            int r = row + dir[0];
            int c = col + dir[1];
            int influence = 0;
            
            // 计算在这个方向的影响力
            while (r >= 0 && r < size && c >= 0 && c < size && influence < 3) {
                if (board[r][c] == player) {
                    influence += 10;
                } else if (board[r][c] == empty) {
                    influence += 5;
                } else {
                    break; // 遇到对手棋子，影响力终止
                }
                r += dir[0];
                c += dir[1];
            }
            
            control += influence;
        }
        
        return control;
    }
    
    // 评估长期潜力
    private int evaluateLongTermPotential(char[][] board, int row, int col, char player, int winCount, GameConfig config) {
        int potential = 0;
        
        // 检查是否能形成多个发展方向
        int developmentPaths = countDevelopmentPaths(board, row, col, player, config);
        potential += developmentPaths * 15;
        
        // 检查是否在关键区域
        if (isInKeyArea(row, col, config.getBoardSize(), winCount)) {
            potential += 20;
        }
        
        // 检查是否能连接分散的棋子
        potential += evaluateConnectionPotential(board, row, col, player, config);
        
        return potential;
    }
    
    // 评估阻碍效果
    private int evaluateObstruction(char[][] board, int row, int col, char opponent, int winCount, GameConfig config) {
        int obstruction = 0;
        
        // 检查是否能阻断对手的潜在连线
        int blockedPaths = countBlockedPaths(board, row, col, opponent, winCount, config);
        obstruction += blockedPaths * 25;
        
        // 检查是否能分割对手的棋子
        if (canSplitOpponentGroups(board, row, col, opponent, config)) {
            obstruction += 30;
        }
        
        return obstruction;
    }
    
    // 获取战略性空位置
    private List<int[]> getStrategicEmptyPositions(char[][] board, GameConfig config) {
        List<int[]> emptyPositions = new ArrayList<>();
        int size = config.getBoardSize();
        char empty = config.getEmptySymbol();
        Set<String> considered = new HashSet<>();
        
        // 只考虑有棋子周围的空位（优化性能）
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (board[i][j] != empty) {
                    // 根据棋盘大小调整搜索范围
                    int searchRange = (size <= 10) ? 2 : 3;
                    for (int di = -searchRange; di <= searchRange; di++) {
                        for (int dj = -searchRange; dj <= searchRange; dj++) {
                            int ni = i + di;
                            int nj = j + dj;
                            if (ni >= 0 && ni < size && nj >= 0 && nj < size && 
                                board[ni][nj] == empty) {
                                String key = ni + "," + nj;
                                if (!considered.contains(key)) {
                                    emptyPositions.add(new int[]{ni, nj});
                                    considered.add(key);
                                }
                            }
                        }
                    }
                }
            }
        }
        
        // 如果棋盘很空，返回中心区域和一些关键点
        if (emptyPositions.isEmpty()) {
            int center = size / 2;
            for (int i = Math.max(0, center - 2); i <= Math.min(size - 1, center + 2); i++) {
                for (int j = Math.max(0, center - 2); j <= Math.min(size - 1, center + 2); j++) {
                    if (board[i][j] == empty) {
                        emptyPositions.add(new int[]{i, j});
                    }
                }
            }
        }
        
        return emptyPositions;
    }
    
    // 检查在指定位置是否获胜
    private boolean checkWinAtPosition(char[][] board, int row, int col, int winCount) {
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};
        
        for (int[] dir : directions) {
            int count = 1; // 当前位置
            
            // 正向计数
            count += countInDirection(board, row, col, dir[0], dir[1], board[row][col]);
            // 反向计数
            count += countInDirection(board, row, col, -dir[0], -dir[1], board[row][col]);
            
            if (count >= winCount) {
                return true;
            }
        }
        return false;
    }
    
    // 单向计数辅助方法
    private int countInDirection(char[][] board, int row, int col, int rowDir, int colDir, char player) {
        int count = 0;
        int r = row + rowDir;
        int c = col + colDir;
        
        while (r >= 0 && r < board.length && c >= 0 && c < board[0].length && 
               board[r][c] == player) {
            count++;
            r += rowDir;
            c += colDir;
        }
        
        return count;
    }
    
    // 以下是一些辅助的简化实现
    private int countDevelopmentPaths(char[][] board, int row, int col, char player, GameConfig config) {
        // 简化实现：计算不同方向的空位数量
        int paths = 0;
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};
        char empty = config.getEmptySymbol();
        
        for (int[] dir : directions) {
            int r = row + dir[0];
            int c = col + dir[1];
            if (r >= 0 && r < board.length && c >= 0 && c < board[0].length && 
                board[r][c] == empty) {
                paths++;
            }
        }
        
        return paths;
    }
    
    private boolean isInKeyArea(int row, int col, int boardSize, int winCount) {
        // 关键区域通常是中心区域
        int center = boardSize / 2;
        int margin = (winCount <= 3) ? 1 : 2;
        return Math.abs(row - center) <= margin && Math.abs(col - center) <= margin;
    }
    
    private int evaluateConnectionPotential(char[][] board, int row, int col, char player, GameConfig config) {
        // 简化实现：检查是否能连接附近的同色棋子
        int connection = 0;
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};
        
        for (int[] dir : directions) {
            int r = row + dir[0];
            int c = col + dir[1];
            if (r >= 0 && r < board.length && c >= 0 && c < board[0].length && 
                board[r][c] == player) {
                connection += 10;
            }
        }
        
        return connection;
    }
    
    private int countBlockedPaths(char[][] board, int row, int col, char opponent, int winCount, GameConfig config) {
        // 简化实现：计算被阻断的对手潜在路径
        int blocked = 0;
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};
        
        for (int[] dir : directions) {
            int r = row + dir[0];
            int c = col + dir[1];
            if (r >= 0 && r < board.length && c >= 0 && c < board[0].length && 
                board[r][c] == opponent) {
                blocked++;
            }
        }
        
        return blocked;
    }
    
    private boolean canSplitOpponentGroups(char[][] board, int row, int col, char opponent, GameConfig config) {
        // 简化实现：检查是否能分割对手的棋子群
        // 这里可以实现更复杂的分割检测逻辑
        return false;
    }
    
    // 模式信息内部类
    private static class PatternInfo {
        public int consecutive;
        public int openEnds;
        public int winCount;
        
        public PatternInfo(int consecutive, int openEnds, int winCount) {
            this.consecutive = consecutive;
            this.openEnds = openEnds;
            this.winCount = winCount;
        }
        
        public int getOffenseScore() {
            // 根据胜利条件调整进攻评分
            if (consecutive >= winCount) return 1000;
            if (consecutive == winCount - 1 && openEnds >= 1) return 100;
            if (consecutive == winCount - 2 && openEnds >= 1) return 30;
            if (consecutive >= 2) return consecutive * 5 + openEnds * 3;
            return 0;
        }
        
        public int getDefenseScore() {
            // 防守评分通常比进攻评分更高
            return (int)(getOffenseScore() * 1.2);
        }
    }
}